﻿using System.Globalization;
namespace AnalyStock.DataManage;
internal enum UpdateDataType
{
    Insert, Modify, ReWrite
}
internal class CommDataHelper<T> where T : class, new()
{
    /// <summary>
    ///     获取在线数据，使用反射处理扩展在线数据类，较直接new实例牺牲了一些性能
    /// </summary>
    /// <param name="args"> params:stockCode,StartDate,EndDate,TradeDate</param>
    /// <returns></returns>
    internal static async Task<IList<T>> GetDataOnlineAsync(params string[] args)
    {
        IDownDataTemplate<T> iDownData =
             Activator.CreateInstance(GetQueryClassType()) as DownDataTemplate<T>;
        return await iDownData.DownloadOnlineAsync(args).ConfigureAwait(false);
    }
    /// <summary>
    ///     获取在库数据,使用反射处理扩展数据查询类，较直接new实例牺牲了一些性能
    /// </summary>
    /// <param name="args">params:stockCode,StartDate,EndDate,TradeDate</param>
    /// <returns></returns>
    internal static async Task<IList<T>> GetDataOnDbSetAsync(params string[] args)
    {
        IDbTemplate<T> idbTable =
             Activator.CreateInstance(GetQueryClassType(false)) as DbTemplate<T>;
        return await idbTable.QueryDataAsync(args).ConfigureAwait(false);
    }
    private static Type GetQueryClassType(bool isOnline = true)
    {
        var _arrayTypeName = typeof(T).FullName.Split(".");
        //添加多态类命名的前缀
        _arrayTypeName[^1] = $"{(isOnline ? "DownloadOnline_" : "DbQuery_")}{_arrayTypeName.Last()}";
        string _classFullName = string.Join(".", _arrayTypeName);
        Type t = Type.GetType(_classFullName);
        return t switch
        {
            null => throw new Exception($"加载 {_classFullName} 类错误!"),
            _ => t
        };
    }

    /// <summary>
    ///     删除在库数据
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    internal static async Task<int> DeleDataOnDbSetAsync(IList<T> list)
    {
        return await new DbTemplate<T>().DeleDataAsync(list).ConfigureAwait(false);
    }


    /// <summary>
    ///     保存到库文件
    /// </summary>
    /// <param name="list"></param>
    /// <param name="isReWriteOrInsert"></param>
    /// <param name="args">stockCode</param>
    /// <returns></returns>

    //stockCode参数主要是指明数据文件的路径及名称。
    internal static async Task<int> SaveDataToDbSetAsync(IList<T> list, string stockCode = default)
    {
        (UpdateDataType saveType, string code) = typeof(T) switch
        {
            { Name: nameof(Daily) } => (UpdateDataType.Insert, stockCode), //保存插入记录，编码值不能空,需要导向个股库文件
            { Name: nameof(DynamicFinancialIndex) } => (UpdateDataType.Insert, stockCode),
            { Name: nameof(SelectStock) } => (UpdateDataType.Modify, null), //保存修改或插入记录，编码值为空，导向SeleStock文件
            { Name: nameof(Conception) } => (UpdateDataType.Modify, null),
            { Name: nameof(StockNote) } => (UpdateDataType.Modify, null),
            { Name: nameof(BakDaily) } => (UpdateDataType.ReWrite, null), //保存使用重写覆盖，编码值为空，导向Basic库文件
            { Name: nameof(StockBasic) } => (UpdateDataType.ReWrite, null),
            _ => throw new ArgumentNullException(message: "更新时没有匹配数据结构", null)
        };
        return await new DbTemplate<T>().SaveDataAsync(list, saveType, code)
                                        .ConfigureAwait(false);
    }
}

/// <summary>
/// 腾讯在线数据接口扩展处理
/// </summary>
internal static class DownLoadExtensions_Tencent
{

    internal static async Task<IList<MinuteData>> GetMinuteDataOnTencentAsync(this string stockCode)
    {
        var _list = new List<MinuteData>();
        //获取分时数据
        var _mintueInfor = await CommDataMethod<MinuteOfTencent>
                                        .GetDataOnlineAsync(stockCode)
                                        .ConfigureAwait(false);
        if (_mintueInfor.FirstOrDefault()?.Data.Length == 0) return _list;
        var _minuteDatas = _mintueInfor.FirstOrDefault().Data;
        //获取当日及时交易信息
        var _daily = await CommDataMethod<DailyOfTencent>
                                .GetDataOnlineAsync(stockCode)
                                .ConfigureAwait(false);
        var _currentDate = _mintueInfor.FirstOrDefault().Date;
        var _yestClose = _daily.FirstOrDefault().YestClose;
        //是否新三板
        bool _isNEEQ = stockCode.StartsWith("68");
        float _currentPrice, _accumVol, _accumAmount, _lastAccumVol = default;
        foreach (var strValue in _minuteDatas)
        {
            var _item = strValue.Split(" ");
            _currentPrice = _item[1].ConvertToFloat();
            //新三板传递单位为“股”，其他为"手"，统一转化为"手"
            _accumVol = _isNEEQ
                            ? _item[2].ConvertToFloat() / 100.0f
                            : _item[2].ConvertToFloat();
            _accumAmount = _item.Length > 2
                            ? _item[3].ConvertToFloat()
                            : _currentPrice * _accumVol;
            _list.Add(new MinuteData
            {
                Ts_code = stockCode,
                Date = _currentDate,
                Mintue = _item[0],
                Price_timely = _currentPrice,
                Volume = _accumVol - _lastAccumVol,
                Yestclose = _yestClose,
                Price_mean = _accumVol > 0 ? _accumAmount / (_accumVol * 100.0f) : 0
            });
            _lastAccumVol = _accumVol;
        }
        return _list.Take(242).ToList();
    }
    internal static async Task<IList<Daily>> AddCurrentDailyOnlineAsync(this IList<Daily> list)
    {
        if (list.IsNullOrEmpty()) return list;
        var _curr = await GetCurrentDailyOnTencentAsync(list.LastOrDefault().Ts_code);
        if (_curr is null) return list;
        var _tradeDate=_curr.Date[..8];
        if (list.LastOrDefault().Trade_date.Equals(_tradeDate)) return list;        
        list.Add(new Daily
        {
            Trade_date =_tradeDate,            
            Ts_code = list.LastOrDefault().Ts_code,
            Open = _curr.Open,
            High = _curr.High,
            Low = _curr.Low,
            Close = _curr.Close,
            Pre_close = _curr.YestClose,
            Change = _curr.Change,
            Pct_chg = _curr.Pct_chg,
            Vol = _curr.Vol,
            Amount = _curr.Amount,
            Adj_factor=list.Last().Adj_factor          

        });
        return list;
    }
    internal static async Task<DailyOfTencent> GetCurrentDailyOnTencentAsync(string stockCode)
    {
        var _curr = (await CommDataMethod<DailyOfTencent>
                                   .GetDataOnlineAsync(stockCode)
                                   .ConfigureAwait(false)).LastOrDefault();                                                                     
        if (_curr?.Open == 0 && _curr?.Vol == 0) return null;
        return  _curr;
    }

    internal static void AddCurrentDailyByMinute(this IList<Daily> dailies, IList<MinuteData> list)
    {
        if (list.IsNullOrEmpty()) return;
        var (maxPrice, minPrice) = list.MaxMinFloat(n => n.Price_timely);
        var _daily = new Daily
        {
            Ts_code = list[0].Ts_code,
            Trade_date = list[0].Date,
            Pre_close = list[0].Yestclose,
            Open = list[0].Price_timely,
            Close = list[list.Count - 1].Price_timely,
            High = maxPrice,
            Low = minPrice,
            Change = ((maxPrice / minPrice) - 1) * 100.0f,
            Pct_chg = ((list[list.Count - 1].Price_timely / list[0].Yestclose) - 1) * 100.0f,
            Vol = list.Sum(n => n.Volume),
            Amount = list.Sum(n => n.Volume * n.Price_mean) / 10.0f,
            Adj_factor = dailies.LastOrDefault().Adj_factor
        };
        var _datesgap = _daily.Trade_date.ConvertToDate()
                        - dailies.Last().Trade_date.ConvertToDate();
        //如果日期不同才可以追加在线记录
        //交易日之间间隔最多为国庆+周末，12天.平移K线时适当追加记录
        if (_datesgap.Days is > 0 and < 12)
        {
            dailies.Add(_daily);
        }
        if (_datesgap.Days is 0)
        {
            dailies[^1] = _daily;
        }
    }
}